/*
 * Declarations shared between the different parts of the ipcio module
 */

#include "netioconf.h"

#if defined(__unix__)
	#define _POSIX_C_SOURCE 200112L
	#include <unistd.h>
//	#if defined(_POSIX_VERSION) && (_POSIX_VERSION >= 200112L)
//		#define PLAT_POSIX
//	#else
//		#error Unsupported Unix platform, _POSIX_VERSION < 200112
//	#endif
	#ifdef HAVE_SYS_TYPES_H
		#include <sys/types.h>
	#endif
	#ifdef HAVE_SYS_SOCKET_H
		#include <sys/socket.h>
	#endif
	#include <sys/time.h>
	#include <fcntl.h>
	#ifdef HAVE_INET
		#include <netinet/in.h>
		#include <netdb.h>
	#endif
	#ifdef HAVE_UNIX
		#include <sys/un.h>
	#endif
	#ifdef HAVE_ATALK
		#include <netatalk/at.h>
	#endif
	#ifdef HAVE_IRDA
		#include <linux/irda.h>
	#endif
	#if defined(_POSIX_IPV6) && (_POSIX_IPV6 > 0)
		#define HAVE_INET6
	#endif

#elif defined(_WIN32)

	#define _WIN32_WINNT 0x0501  /* select WinXP compatibility for Python 3.3, see PEP 11 */
	#define WIN32_LEAN_AND_MEAN
	#include <winsock2.h>
	#if defined(HAVE_INET4) || defined(HAVE_INET6)
		#include <ws2tcpip.h>
	#endif
	#ifdef HAVE_NETBIOS
		#include <wsnetbs.h>
	#endif
	#ifdef HAVE_IPX
		#include <wsipx.h>
	#endif
	#ifdef HAVE_ATALK
		#include <atalkwsh.h>
	#endif
	#ifdef HAVE_IRDA
		#include <af_irda.h>
	#endif
	#ifdef HAVE_BLUETOOTH
		#include <ws2bth.h>
	#endif

	typedef SOCKET Py_sockfd_t;
	#define INVALID_SOCKFD INVALID_SOCKET
	#define BLOCKING_ERROR (WSAGetLastError() == WSAEWOULDBLOCK)
	#define SHUT_RD SD_RECEIVE
	#define SHUT_WR SD_SEND
	#define SHUT_RDWR SD_BOTH

////#include <sdkddkver.h>
////#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= _WIN32_WINNT_WIN2K)
//	#if defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_WIN2K)
//		#define PLAT_WINDOWS
//	#else
//		#error Unsupported Windows platform, _WIN32_WINNT < _WIN32_WINNT_WIN2K
//	#endif

#else

	#error Unsupported platform

#endif

#include "Python.h"

#if defined(PLAT_WINDOWS)

	#define WIN32_LEAN_AND_MEAN
	//#define FD_SETSIZE 128
	#include <winsock2.h>
	#include <ws2tcpip.h>
//	typedef struct sockaddr Py_sockaddr_t;
	typedef SOCKET Py_sockfd_t;
	#define INVALID_SOCKFD INVALID_SOCKET
	#define BLOCKING_ERROR (WSAGetLastError() == WSAEWOULDBLOCK)
	#define SHUT_RD SD_RECEIVE
	#define SHUT_WR SD_SEND
	#define SHUT_RDWR SD_BOTH
	#define HAVE_INET

#elif defined(PLAT_POSIX)

	#include <sys/socket.h>
//	typedef struct sockaddr Py_sockaddr_t
	typedef int Py_sockfd_t;
	#define INVALID_SOCKFD -1
	#define BLOCKING_ERROR (errno == EWOULDBLOCK || errno == EAGAIN)
	#define HAVE_INET
	#define HAVE_UNIX

#endif

/* Concrete classes */

extern PyTypeObject PySockAddr_Type;
extern PyTypeObject PySocketIO_Type;
extern PyTypeObject PyPassiveSocket_Type;
extern PyTypeObject PyBufferedSequential_Type;

/* PySocketIO interface */

typedef struct {
	PyObject_HEAD
	Py_sockfd_t fd;
	unsigned short readable   : 1;
	unsigned short writable   : 1;
	unsigned short closefd    : 1;
//	unsigned short listening  : 1;
	unsigned short connecting : 1;
	unsigned short urgentmode : 1;
    PyObject *weakref;
    PyObject *dict;
} PySocketIOObject;

#define PySocketIO_Check(op) (PyObject_TypeCheck((op), &PySocketIO_Type) || \
							  PyObject_TypeCheck((op), &PyPassiveSocket_Type))

#define PySocketIO_IsClosed(op) ((op)->fd == INVALID_SOCKFD)
#define PySocketIO_IsReadable(op) ((op)->readable && !(obj)->listening && !(obj)->connecting)
#define PySocketIO_IsWritable(op) ((op)->writable && !(obj)->listening && !(obj)->connecting)

/* PySockAddr interface */

/* This struct includes a uintptr_t member, which should force at least 8 byte
   alignment on 64 bit platforms and at least 4 byte alignment on 32 bit
   platforms, achieving the same alignment as sockaddr_storage but with
   variable size. */
typedef struct {
	PyObject_VAR_HEAD
	Py_uintptr_t ob_item[1];
//	char ob_item[1];
} PySockAddrObject;

#define PySockAddr_Check(op) PyObject_TypeCheck(op, &PySockAddr_Type)
#define PySockAddr_CheckExact(op) (Py_TYPE(op) == &PySockAddr_Type)

PyObject *PySockAddr_New(int family);
PyObject *PySockAddr_FromAddr(const void *addr, Py_ssize_t size);
PyObject *PySockAddr_FromName(const char *name, const char *mode, int flags);
PyObject *PySockAddr_ListAllFromName(const char *name, const char *mode, int flags);
PyObject *PySockAddr_GetName(PyObject *addrobj, int flags);

#define PySockAddr_GET_SIZE(op) Py_SIZE(op)
#define PySockAddr_GET_ADDR(op) ((struct sockaddr *) ((PySockAddrObject*)(op))->ob_item)
//#define PySockAddr_GET_ADDRT(op, ty) ((ty*) ((PySockAddrObject*)(op))->ob_item)
//#define PySockAddr_GET_SADDR(op) PySockAddr_GET_ADDRT(op, struct sockaddr)

